
#include <stdio.h>
#include <string.h>
#include <float.h>
#include "unity.h"
#include "serialize/serialize.h"

// Define a test structure
COT_DEFINE_STRUCT_TYPE(test_t,
                       ((UINT8_T)(val_1)(1))
                       ((INT32_T)(val_2)(1))
                       ((DOUBLE_T)(val_3)(2))
                       ((STRING_T)(szDesc)(32))
                      )

// Declare the test structure variable
COT_DEFINE_STRUCT_VARIABLE(test_t, testVal);

void setUp(void)
{
    // Set up any necessary initialization before each test
    COT_INIT_STRUCT_VARIABLE(test_t, testVal);
}

void tearDown(void)
{
    // Clean up any resources after each test
}

void test_SerializeAndParse(void)
{
    uint8_t buf[100];

    // COT_DEFINE_STRUCT_VARIABLE(test_t, test);

    // Set values in the test structure
    testVal.val_1 = 5;
    testVal.val_2 = -15;
    testVal.val_3[0] = 2.25;
    testVal.val_3[1] = 1.75;
    sprintf(testVal.szDesc, "name");

    // Serialize the test structure
    int serializedSize = testVal.Serialize(buf, &testVal);

    // Assert that the serialized size is greater than zero
    TEST_ASSERT_GREATER_THAN(0, serializedSize);

    // Create a new instance of the test structure for parsing
    COT_DEFINE_STRUCT_VARIABLE(test_t, parsedTestVal);

    // Parse the serialized data into the new test structure
    int parsedSize = parsedTestVal.Parse(&parsedTestVal, buf);

    // Assert that the parsed size is equal to the serialized size
    TEST_ASSERT_EQUAL_INT(serializedSize, parsedSize);

    // Assert that the parsed values match the original values
    TEST_ASSERT_EQUAL_INT(testVal.val_1, parsedTestVal.val_1);
    TEST_ASSERT_EQUAL_INT(testVal.val_2, parsedTestVal.val_2);
    TEST_ASSERT_EQUAL_FLOAT(testVal.val_3[0], parsedTestVal.val_3[0]);
    TEST_ASSERT_EQUAL_FLOAT(testVal.val_3[1], parsedTestVal.val_3[1]);
    TEST_ASSERT_EQUAL_STRING(testVal.szDesc, parsedTestVal.szDesc);
}

void test_SerializeAndParse_EmptyString(void)
{
    uint8_t buf[100];

    // Set values in the test structure
    testVal.val_1 = 5;
    testVal.val_2 = -15;
    testVal.val_3[0] = 2.25;
    testVal.val_3[1] = 1.75;
    sprintf(testVal.szDesc, ""); // Empty string

    // Serialize the test structure
    int serializedSize = testVal.Serialize(buf, &testVal);

    // Assert that the serialized size is greater than zero
    TEST_ASSERT_GREATER_THAN(0, serializedSize);

    // Create a new instance of the test structure for parsing
    COT_DEFINE_STRUCT_VARIABLE(test_t, parsedTestVal);

    // Parse the serialized data into the new test structure
    int parsedSize = parsedTestVal.Parse(&parsedTestVal, buf);

    // Assert that the parsed size is equal to the serialized size
    TEST_ASSERT_EQUAL_INT(serializedSize, parsedSize);

    // Assert that the parsed values match the original values
    TEST_ASSERT_EQUAL_INT(testVal.val_1, parsedTestVal.val_1);
    TEST_ASSERT_EQUAL_INT(testVal.val_2, parsedTestVal.val_2);
    TEST_ASSERT_EQUAL_FLOAT(testVal.val_3[0], parsedTestVal.val_3[0]);
    TEST_ASSERT_EQUAL_FLOAT(testVal.val_3[1], parsedTestVal.val_3[1]);
    TEST_ASSERT_EQUAL_STRING(testVal.szDesc, parsedTestVal.szDesc);
}

void test_SerializeAndParse_LargeString(void)
{
    uint8_t buf[100];

    // Set values in the test structure
    testVal.val_1 = 5;
    testVal.val_2 = -15;
    testVal.val_3[0] = 2.25;
    testVal.val_3[1] = 1.75;

    // Create a large string (exceeding the defined size)
    char largeString[50];
    memset(largeString, 'A', sizeof(largeString) - 1);
    largeString[sizeof(largeString) - 1] = '\0';

    strcpy(testVal.szDesc, largeString);

    // Serialize the test structure
    int serializedSize = testVal.Serialize(buf, &testVal);

    // Assert that the serialized size is greater than zero
    TEST_ASSERT_GREATER_THAN(0, serializedSize);

    // Create a new instance of the test structure for parsing
    COT_DEFINE_STRUCT_VARIABLE(test_t, parsedTestVal);

    // Parse the serialized data into the new test structure
    int parsedSize = parsedTestVal.Parse(&parsedTestVal, buf);

    // Assert that the parsed size is equal to the serialized size
    TEST_ASSERT_EQUAL_INT(serializedSize, parsedSize);

    // Assert that the parsed values match the original values
    TEST_ASSERT_EQUAL_INT(testVal.val_1, parsedTestVal.val_1);
    TEST_ASSERT_EQUAL_INT(testVal.val_2, parsedTestVal.val_2);
    TEST_ASSERT_EQUAL_FLOAT(testVal.val_3[0], parsedTestVal.val_3[0]);
    TEST_ASSERT_EQUAL_FLOAT(testVal.val_3[1], parsedTestVal.val_3[1]);
    TEST_ASSERT_EQUAL_STRING(testVal.szDesc, parsedTestVal.szDesc);
}

void test_SerializeAndParse_ZeroValues(void)
{
    uint8_t buf[100];

    // Set values in the test structure
    testVal.val_1 = 0;
    testVal.val_2 = 0;
    testVal.val_3[0] = 0.0;
    testVal.val_3[1] = 0.0;
    sprintf(testVal.szDesc, "Zero values");

    // Serialize the test structure
    int serializedSize = testVal.Serialize(buf, &testVal);

    // Assert that the serialized size is greater than zero
    TEST_ASSERT_GREATER_THAN(0, serializedSize);

    // Create a new instance of the test structure for parsing
    COT_DEFINE_STRUCT_VARIABLE(test_t, parsedTestVal);

    // Parse the serialized data into the new test structure
    int parsedSize = parsedTestVal.Parse(&parsedTestVal, buf);

    // Assert that the parsed size is equal to the serialized size
    TEST_ASSERT_EQUAL_INT(serializedSize, parsedSize);

    // Assert that the parsed values match the original values
    TEST_ASSERT_EQUAL_INT(testVal.val_1, parsedTestVal.val_1);
    TEST_ASSERT_EQUAL_INT(testVal.val_2, parsedTestVal.val_2);
    TEST_ASSERT_EQUAL_FLOAT(testVal.val_3[0], parsedTestVal.val_3[0]);
    TEST_ASSERT_EQUAL_FLOAT(testVal.val_3[1], parsedTestVal.val_3[1]);
    TEST_ASSERT_EQUAL_STRING(testVal.szDesc, parsedTestVal.szDesc);
}

void test_SerializeAndParse_NegativeValues(void)
{
    uint8_t buf[100];

    // Set values in the test structure
    testVal.val_1 = -10;
    testVal.val_2 = -20;
    testVal.val_3[0] = -2.5;
    testVal.val_3[1] = -3.5;
    sprintf(testVal.szDesc, "Negative values");

    // Serialize the test structure
    int serializedSize = testVal.Serialize(buf, &testVal);

    // Assert that the serialized size is greater than zero
    TEST_ASSERT_GREATER_THAN(0, serializedSize);

    // Create a new instance of the test structure for parsing
    COT_DEFINE_STRUCT_VARIABLE(test_t, parsedTestVal);

    // Parse the serialized data into the new test structure
    int parsedSize = parsedTestVal.Parse(&parsedTestVal, buf);

    // Assert that the parsed size is equal to the serialized size
    TEST_ASSERT_EQUAL_INT(serializedSize, parsedSize);

    // Assert that the parsed values match the original values
    TEST_ASSERT_EQUAL_INT(testVal.val_1, parsedTestVal.val_1);
    TEST_ASSERT_EQUAL_INT(testVal.val_2, parsedTestVal.val_2);
    TEST_ASSERT_EQUAL_FLOAT(testVal.val_3[0], parsedTestVal.val_3[0]);
    TEST_ASSERT_EQUAL_FLOAT(testVal.val_3[1], parsedTestVal.val_3[1]);
    TEST_ASSERT_EQUAL_STRING(testVal.szDesc, parsedTestVal.szDesc);
}

void test_SerializeAndParse_MaxValues(void)
{
    uint8_t buf[100];

    // Set values in the test structure
    testVal.val_1 = UINT8_MAX;
    testVal.val_2 = INT32_MAX;
    testVal.val_3[0] = DBL_MAX;
    testVal.val_3[1] = FLT_MAX;
    sprintf(testVal.szDesc, "Max values");

    // Serialize the test structure
    int serializedSize = testVal.Serialize(buf, &testVal);

    // Assert that the serialized size is greater than zero
    TEST_ASSERT_GREATER_THAN(0, serializedSize);

    // Create a new instance of the test structure for parsing
    COT_DEFINE_STRUCT_VARIABLE(test_t, parsedTestVal);

    // Parse the serialized data into the new test structure
    int parsedSize = parsedTestVal.Parse(&parsedTestVal, buf);

    // Assert that the parsed size is equal to the serialized size
    TEST_ASSERT_EQUAL_INT(serializedSize, parsedSize);

    // Assert that the parsed values match the original values
    TEST_ASSERT_EQUAL_INT(testVal.val_1, parsedTestVal.val_1);
    TEST_ASSERT_EQUAL_INT(testVal.val_2, parsedTestVal.val_2);
    TEST_ASSERT_EQUAL_FLOAT(testVal.val_3[0], parsedTestVal.val_3[0]);
    TEST_ASSERT_EQUAL_FLOAT(testVal.val_3[1], parsedTestVal.val_3[1]);
    TEST_ASSERT_EQUAL_STRING(testVal.szDesc, parsedTestVal.szDesc);
}

void test_SerializeAndParse_NonAsciiCharacters(void)
{
    uint8_t buf[100];

    // Set values in the test structure
    testVal.val_1 = 10;
    testVal.val_2 = 20;
    testVal.val_3[0] = 2.5;
    testVal.val_3[1] = 3.5;
    sprintf(testVal.szDesc, "Non-ASCII characters: äëïöü");

    // Serialize the test structure
    int serializedSize = testVal.Serialize(buf, &testVal);

    // Assert that the serialized size is greater than zero
    TEST_ASSERT_GREATER_THAN(0, serializedSize);

    // Create a new instance of the test structure for parsing
    COT_DEFINE_STRUCT_VARIABLE(test_t, parsedTestVal);

    // Parse the serialized data into the new test structure
    int parsedSize = parsedTestVal.Parse(&parsedTestVal, buf);

    // Assert that the parsed size is equal to the serialized size
    TEST_ASSERT_EQUAL_INT(serializedSize, parsedSize);

    // Assert that the parsed values match the original values
    TEST_ASSERT_EQUAL_INT(testVal.val_1, parsedTestVal.val_1);
    TEST_ASSERT_EQUAL_INT(testVal.val_2, parsedTestVal.val_2);
    TEST_ASSERT_EQUAL_FLOAT(testVal.val_3[0], parsedTestVal.val_3[0]);
    TEST_ASSERT_EQUAL_FLOAT(testVal.val_3[1], parsedTestVal.val_3[1]);
    TEST_ASSERT_EQUAL_STRING(testVal.szDesc, parsedTestVal.szDesc);
}

void test_SerializeAndParse_LongString(void)
{
    uint8_t buf[100];

    // Set values in the test structure
    testVal.val_1 = 5;
    testVal.val_2 = 15;
    testVal.val_3[0] = 2.25;
    testVal.val_3[1] = 1.75;
    strcpy(testVal.szDesc, "This is a long string that exceeds the buffer size");

    // Serialize the test structure
    int serializedSize = testVal.Serialize(buf, &testVal);

    // Assert that the serialized size is greater than zero
    TEST_ASSERT_GREATER_THAN(0, serializedSize);

    // Create a new instance of the test structure for parsing
    COT_DEFINE_STRUCT_VARIABLE(test_t, parsedTestVal);

    // Parse the serialized data into the new test structure
    int parsedSize = parsedTestVal.Parse(&parsedTestVal, buf);

    // Assert that the parsed size is equal to the serialized size
    TEST_ASSERT_EQUAL_INT(serializedSize, parsedSize);

    // Assert that the parsed values match the original values
    TEST_ASSERT_EQUAL_INT(testVal.val_1, parsedTestVal.val_1);
    TEST_ASSERT_EQUAL_INT(testVal.val_2, parsedTestVal.val_2);
    TEST_ASSERT_EQUAL_FLOAT(testVal.val_3[0], parsedTestVal.val_3[0]);
    TEST_ASSERT_EQUAL_FLOAT(testVal.val_3[1], parsedTestVal.val_3[1]);
    TEST_ASSERT_EQUAL_STRING(testVal.szDesc, parsedTestVal.szDesc);
}

// Run the test suite
int main(void)
{
    UNITY_BEGIN();
    RUN_TEST(test_SerializeAndParse);
    RUN_TEST(test_SerializeAndParse_EmptyString);
    RUN_TEST(test_SerializeAndParse_LargeString);
    RUN_TEST(test_SerializeAndParse_ZeroValues);
    RUN_TEST(test_SerializeAndParse_NegativeValues);

    RUN_TEST(test_SerializeAndParse_MaxValues);
    RUN_TEST(test_SerializeAndParse_NonAsciiCharacters);
    RUN_TEST(test_SerializeAndParse_LongString);

    UNITY_END();

    return 0;
}
